#include "HttpContext.h"

#include "../Buffer.h"

bool HttpContext::processRequestLine(const char *begin, const char *end) {
    bool succeed = false;
    const char *start = begin;
    const char *space = std::find(start, end, ' ');
    // http请求的第一行 : GET /login HTTP/1.1
    if (space != end && request_.setMethod(start, space)) {
        // 第一个空格就是请求方法
        start = space + 1;
        space = std::find(start, end, ' ');
        if (space != end) {
            // 第二个空格, 解析请求路径
            const char *question = std::find(start, space, '?');
            // 看看是否有query参量
            if (question != space) {
                request_.setPath(start, question);
                request_.setQuery(question, space);
            } else {
                request_.setPath(start, space);
            }
            start = space + 1;
            succeed = end - start == 8 && std::equal(start, end - 1, "HTTP/1.");
            if (succeed) {
                if (*(end - 1) == '1') {
                    request_.setVersion(HttpRequest::kHttp11);
                } else if (*(end - 1) == '0') {
                    request_.setVersion(HttpRequest::kHttp10);
                } else {
                    succeed = false;
                }
            }
        }
    }
    return succeed;
}

// 当有异常的时候返回error
bool HttpContext::parseRequest(Buffer *buf, Timestamp receiveTime) {
    bool ok = true;
    bool hasMore = true;
    while (hasMore) {
        if (state_ == kExpectRequestLine) {
            const char *crlf = buf->findCRLF();
            if (crlf) {
                ok = processRequestLine(buf->peek(), crlf);
                // 如果寻找到的话解析第一行, 将第一行存入req
                if (ok) {
                    request_.setReceiveTime(receiveTime);
                    buf->retrieveUntil(crlf + 2);
                    state_ = kExpectHeaders;
                    // 进入下一个状态
                } else {
                    hasMore = false;
                    // 解析失败, 不继续解析
                }
            } else {
                hasMore = false;
            }
        } else if (state_ == kExpectHeaders) {
            // 解析请求头
            const char *crlf = buf->findCRLF();
            if (crlf) {
                const char *colon = std::find(buf->peek(), crlf, ':');
                if (colon != crlf) {
                    request_.addHeader(buf->peek(), colon, crlf);
                } else {
                    // empty line, end of header, 没有找到colon表示可能是空行, 也就是请求头结束了
                    // FIXME:
                    state_ = kExpectBody;
                }
                buf->retrieveUntil(crlf + 2);
                // 移动指针往后读取
            } else {
                hasMore = false;
            }
        } else if (state_ == kExpectBody) {
            // FIXME: 封装请求体
            if (buf->readableBytes() == 0) {
                state_ = kGotAll;
                hasMore = false;
            }else{
                // FIXME : http报文解析
                const char * end = buf->beginWrite();
                const char * and_ = std::find(buf->peek(), end, '&');
                // 获取一行数据, 找不到也没事, 因为可能是最后一行的结果
                const char * equal = std::find(buf->peek(), and_, '=');
                if (equal != and_){
                    // 说明有一行数据, 进行解析输出
                    request_.addBody(buf->peek(), equal, and_);
                    if(and_ == end){
                        buf->retrieveAll();
                    }else{
                        buf->retrieveUntil(and_ + 1);
                    }
                    // 移动指针往后读取
                }else{
                    state_ = kGotAll;
                    hasMore = false;
                }
            }
        }
    }
    return ok;
}

/* 下面是两个请求方式的请求体 */

// POST / HTTP/1.1
// Content-Type: application/x-www-form-urlencoded
// Content-Length: 31
// User-Agent: EOLINKER
// Accept: */*
// Eo-Token: cbc6ce5a-08aa-4421-964e-71feac6c02c6
// Host: 175.178.51.126:8200
// Connection: close
//
// username=123456&password=123456

// POST / HTTP/1.1
// Content-Type: application/json
// Content-Length: 45
// User-Agent: EOLINKER
// Accept: */*
// Eo-Token: 6e12d767-0280-476f-8dfb-414f1678fb58
// Host: 175.178.51.126:8200
// Connection: close
//
// {"username":"username","password":"password"}